# service/parse/oss_upload.py
import io
import os

import oss2

from common.exception.exception import BusiException
from common.exception.exception_enum import BusiExceptionEnum
from common.log.logging import log
from common.oss.oss import OssApi, OssObject
from common.utils.id_utils import get_uuid


class OssAliyun(OssApi):

    def __init__(self, access_key_id: str, access_key_secret: str, endpoint: str, default_bucket: str):
        self.auth = oss2.Auth(access_key_id, access_key_secret)
        self.endpoint = endpoint
        self.default_bucket = default_bucket

    def upload(self, filename: str, stream: io.IOBase) -> OssObject:
        """
       文件上传到默认的bucket
       :param filename: 文件名称
       :param stream: 上传的文件
       :return: OssObject
       """
        return self.upload_to_bucket(self.default_bucket, filename, stream)

    def upload_to_bucket(self, bucket_name: str, filename: str, stream: io.IOBase) -> OssObject:
        """
       上传文件到阿里云 OSS。

       参数:
       - file: io.IOBase 对象，表示上传的文件。

       返回:
       - OssObject 对象，包含桶名称和对象 ID。
       """
        if not stream:
            raise BusiException(BusiExceptionEnum.NO_FILE_PART)

        try:
            unique_filename = f"{get_uuid()}{os.path.splitext(filename)[1]}"
            bucket = oss2.Bucket(self.auth, self.endpoint, bucket_name)

            if not self.exists_bucket(bucket_name):
                log.info(f"create bucket {bucket_name} Success")
                bucket.create_bucket()

            result = bucket.put_object(unique_filename, stream)
            if result.status == 200:
                log.info(f'File {filename} successfully uploaded to {bucket_name}')
                return OssObject(bucket_name, unique_filename)
            else:
                log.error(f'Failed to upload file: {result.status}, {result.read()}')
                raise BusiException(BusiExceptionEnum.OSS_FILE_UPLOAD_ERROR)
        except Exception as e:
            log.error(f'Error uploading file: {e}')
            raise BusiException(BusiExceptionEnum.OSS_FILE_UPLOAD_ERROR)

    def get_object(self, object_id: str):
        return self.get_object_from_bucket(self.default_bucket, object_id)

    def get_object_from_bucket(self, bucket_name: str, object_id: str) -> io.IOBase:
        """
        从存储服务中获取对象。

        参数:
        - bucket_name: bucket名称
        - object_id: 对象 ID

        返回:
        - io.IOBase 对象，表示获取的文件。
        """
        try:
            bucket = oss2.Bucket(self.auth, self.endpoint, bucket_name)

            if not bucket.object_exists(object_id):
                raise BusiException(BusiExceptionEnum.OSS_OBJECT_NOT_EXISTS)
            obj = bucket.get_object(object_id)
            if obj is None:
                raise BusiException(BusiExceptionEnum.OSS_OBJECT_NOT_EXISTS)
            object_stream = io.BytesIO(obj.read())
            object_stream.seek(0)
            log.info(f'File {object_id} successfully retrieved from {bucket_name}')
            return object_stream
        except Exception as e:
            log.error(f'Error retrieving file: {e}')
            raise BusiException(BusiExceptionEnum.OSS_FILE_RETRIEVAL_ERROR)

    def exists_bucket(self, bucket_name: str):
        service = oss2.Service(self.auth, self.endpoint)
        buckets = service.list_buckets(prefix=bucket_name).buckets
        # 过滤buckets，获取bucket_name等于bucket_name的数量是否大于0
        return len([bucket for bucket in buckets if bucket.name == bucket_name]) > 0
